/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package botobjects;

import interfaces.BotObject;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import main.Constants;
import main.UserCentral;

import org.apache.log4j.Logger;

import tools.StringTools;

import commandhandlers.UserHandler;

import database.DBConnectionFactory;

/**
 * This class represents a user
 * 
 * 
 */
public class User implements BotObject {
   /**
    * Removes the specified user
    * 
    * @param args
    * @return true if the user was successfully deleted
    */
   public static boolean deleteFromDB(final String... args) {
	  boolean out = false;
	  if (args.length < 1)
		 return out;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM " + "admins WHERE mainnick = ? AND fullaccess = true");
		 ps.setString(1, args[0]);
		 rs = ps.executeQuery();
		 if (!rs.next()) {
			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM kdmember WHERE mainnick = ?");
			ps.setString(1, args[0]);

			if (ps.executeUpdate() == 1) {
			   UserCentral.getInstance().unauthenticateUser(args[0]);
			   out = true;
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns a User object for the specified user
    * 
    * @param nick
    * @return a User object. Returns null if no user is found
    */
   public static User getUser(final String nick) {
	  if (StringTools.isNullOrEmpty(nick))
		 return null;
	  User out = null;
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM admins WHERE mainnick = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();

		 boolean isAdmin = rs.next();

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("SELECT * FROM nickname WHERE mainnick = ?");
		 ps.setString(1, nick);
		 rs = ps.executeQuery();

		 List<String> nickList = new LinkedList<String>();
		 while (rs.next()) {
			nickList.add(rs.getString("name"));
		 }

		 ContactInfo ci = ContactInfo.getContactInfo(nick);

		 if (ci != null) {
			out = new User(nick, nickList, isAdmin, ci);
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns a list of all users currently playing a province
    * 
    * @return a List of User objects
    */
   public static List<User> getUsers() {
	  List<User> out = new LinkedList<User>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 List<String> nicks = new LinkedList<String>();
		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("SELECT * FROM kdmember");
		 rs = ps.executeQuery();

		 while (rs.next()) {
			nicks.add(rs.getString("mainnick"));
		 }

		 for (String nick : nicks) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM admins WHERE mainnick = ?");
			ps.setString(1, nick);
			rs = ps.executeQuery();

			boolean isAdmin = rs.next();

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM nickname WHERE mainnick = ?");
			ps.setString(1, nick);
			rs = ps.executeQuery();

			List<String> nickList = new LinkedList<String>();
			while (rs.next()) {
			   nickList.add(rs.getString("name"));
			}

			ContactInfo ci = ContactInfo.getContactInfo(nick);

			if (ci != null) {
			   out.add(new User(nick, nickList, isAdmin, ci));
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private String mainNick = "";

   private List<String> nickList = new LinkedList<String>();

   private Boolean isAdmin = false;

   private ContactInfo contactInfo = null;

   public User(final String mainNick) {
	  this(mainNick, null, null, null);
   }

   public User(final String mainNick, final List<String> nickList, final Boolean isAdmin, final ContactInfo contactInfo) {
	  this.mainNick = mainNick;
	  this.nickList = nickList;
	  this.isAdmin = isAdmin;
	  this.contactInfo = contactInfo;
   }

   public ContactInfo getContactInfo() {
	  return contactInfo;
   }

   @Override
   public List<String> getIRCOutput(final int outputType, final String... args) {
	  return new LinkedList<String>();
   }

   public String getMainNick() {
	  return mainNick;
   }

   public List<String> getNickList() {
	  return nickList;
   }

   @Override
   public Map<String, Object> getRPCOutput(final int... includes) {
	  Map<String, Object> out = new HashMap<String, Object>();
	  if (StringTools.isNullOrEmpty(getMainNick()) || getNickList() == null || isAdmin() == null)
		 return out;
	  out.put("Main Nick", getMainNick());
	  out.put("Nick List", getNickList());
	  out.put("Is Admin", isAdmin());
	  if (includes.length == 1 && includes[0] == Constants.USER_INCLUDE_CONTACTS && getContactInfo() != null) {
		 out.putAll(getContactInfo().getRPCOutput());
	  }
	  return out;
   }

   public Boolean isAdmin() {
	  return isAdmin;
   }

   @Override
   public boolean saveToDB() {
	  boolean out = false;
	  if (StringTools.isNullOrEmpty(getMainNick()))
		 return out;
	  PreparedStatement ps = null;
	  try {
		 if (nickList == null && isAdmin == null && contactInfo == null) {
			deleteFromDB(getMainNick());

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO " + "kdmember VALUES(0,0,'Unknown',?,'Unknown','')");
			ps.setString(1, getMainNick());
			if (ps.executeUpdate() != 1)
			   return false;

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM nickname WHERE mainnick = ?");
			ps.setString(1, getMainNick());
			ps.executeUpdate();

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO nickname VALUES (?,?)");
			ps.setString(1, getMainNick());
			ps.setString(2, getMainNick());
			if (ps.executeUpdate() != 1)
			   return false;

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM idle WHERE mainnick = ?");
			ps.setString(1, getMainNick());
			ps.executeUpdate();

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("INSERT INTO idle VALUES(?,?,?,?,?,?,?,?)");
			ps.setString(1, getMainNick());
			ps.setTimestamp(2, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(3, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(4, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(5, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(6, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(7, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.setTimestamp(8, new Timestamp(Calendar.getInstance().getTimeInMillis()));
			ps.executeUpdate();

			try {
			   ps.close();
			} catch (final Exception e) {
			}

			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("DELETE FROM kdmemberarchive WHERE mainnick = ?");
			ps.setString(1, getMainNick());

			UserHandler.setPassword(getMainNick(), "password", true);
		 } else {
			if (getNickList() != null) {
			   for (String nick : getNickList()) {
				  ps = DBConnectionFactory.getConnectionHandler().getConnection()
						.prepareStatement("INSERT INTO nickname VALUES(?,?)");
				  ps.setString(1, nick);
				  ps.setString(2, getMainNick());
				  ps.executeUpdate();
			   }
			}
			if (isAdmin() != null) {
			   if (isAdmin()) {
				  ps = DBConnectionFactory.getConnectionHandler().getConnection()
						.prepareStatement("INSERT INTO admins VALUES(?,default)");
				  ps.setString(1, getMainNick());
				  ps.executeUpdate();
			   } else {
				  ps = DBConnectionFactory.getConnectionHandler().getConnection()
						.prepareStatement("DELETE FROM admins WHERE mainnick = ?");
				  ps.setString(1, getMainNick());
				  ps.executeUpdate();
			   }

			}
			if (getContactInfo() != null) {
			   getContactInfo().saveToDB();
			}
		 }

		 out = true;
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }
}
